home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Aminet 1 (Walnut Creek)
/
Aminet - June 1993 [Walnut Creek].iso
/
usenet
/
sources
/
volume89
/
editors
/
stevie36.2
< prev
next >
Wrap
Text File
|
1989-05-12
|
63KB
|
2,771 lines
Path: xanth!ukma!tut.cis.ohio-state.edu!rutgers!apple!oliveb!sun!swap!page
From: page%swap@Sun.COM (Bob Page)
Newsgroups: comp.sources.amiga
Subject: v89i131: stevie - vi editor clone v3.6, Part02/06
Message-ID: <104418@sun.Eng.Sun.COM>
Date: 12 May 89 03:06:25 GMT
Sender: news@sun.Eng.Sun.COM
Lines: 2760
Approved: page@sun.com
Submitted-by: grwalter@watmath.waterloo.edu (Fred Walter)
Posting-number: Volume 89, Issue 131
Archive-name: editors/stevie36.2
# This is a shell archive.
# Remove anything above and including the cut line.
# Then run the rest of the file through 'sh'.
# Unpacked files will be owned by you and have default permissions.
#----cut here-----cut here-----cut here-----cut here----#
#!/bin/sh
# shar: SHell ARchive
# Run the following text through 'sh' to create:
# cmdline.c
# dec.c
# dos.c
# dos.h
# edit.c
# env.h
# fileio.c
# format_l.c
# help.c
# inc.c
# keymap.h
# linefunc.c
# macros.h
# main.c
# This is archive 2 of a 6-part kit.
# This archive created: Thu May 11 19:41:25 1989
echo "extracting cmdline.c"
sed 's/^X//' << \SHAR_EOF > cmdline.c
X/*
X * STEVIE - Simply Try this Editor for VI Enthusiasts
X *
X * Code Contributions By : Tim Thompson twitch!tjt
X * Tony Andrews onecom!wldrdg!tony
X * G. R. (Fred) Walter watmath!watcgl!grwalter
X */
X
X#include "stevie.h"
X
Xstatic char *altfile = NULL; /* alternate file */
Xstatic int altline; /* line # in alternate file */
X
Xstatic char *nowrtmsg = "No write since last change (use ! to override)";
X
Xextern char **files; /* used for "n" and "rew" */
Xextern int curfile;
Xextern int numfiles;
X
X/*
X * The next two variables contain the bounds of any range given in a command.
X * If no range was given, both contain null line pointers. If only a single
X * line was given, u_pos will contain a null line pointer.
X */
Xstatic LPtr l_pos, u_pos;
X
Xstatic bool_t interactive; /* TRUE if we're reading a real command line */
X
Xstatic bool_t doecmd();
Xstatic void
Xbadcmd(), doshell(), get_range();
Xstatic LPtr *get_line();
X
X#ifdef MEGAMAX
Xoverlay "cmdline"
X#endif
X
X/*
X * readcmdline() - accept a command line starting with ':', '/', or '?'
X *
X * readcmdline() accepts and processes colon commands and searches. If
X * 'cmdline' is null, the command line is read here. Otherwise, cmdline
X * points to a complete command line that should be used. This is used in
X * main() to handle initialization commands in the environment variable
X * "EXINIT".
X */
Xvoid
Xreadcmdline(firstc, cmdline)
X char firstc; /* either ':', '/', or '?' */
X char *cmdline; /* optional command string */
X{
X char c;
X char buff[CMDBUFFSIZE];
X char cmdbuf[CMDBUFFSIZE];
X char argbuf[CMDBUFFSIZE];
X char *p, *q, *cmd, *arg;
X bool_t literal_next_flag = FALSE;
X
X /*
X * Clear the range variables.
X */
X l_pos.linep = (LINE *) NULL;
X u_pos.linep = (LINE *) NULL;
X
X interactive = (cmdline == NULL);
X
X if (interactive)
X gotocmdline(YES, firstc);
X p = buff;
X if (firstc != ':')
X *p++ = firstc;
X
X if (interactive) {
X /* collect the command string, handling '\b' and @ */
X for (;;) {
X c = vgetc();
X if (c == CTRL('V') && !literal_next_flag) {
X literal_next_flag = TRUE;
X outchar('^');
X continue;
X }
X if (c == '\n' || ((c == '\r' || c == ESC) && (!literal_next_flag)))
X break;
X if ((c == '\b') && (!literal_next_flag)) {
X if (p > buff + (firstc != ':')) {
X p--;
X /*
X * this is gross, but it relies only on 'gotocmdline'
X */
X gotocmdline(YES, firstc == ':' ? ':' : NUL);
X for (q = buff; q < p; q++)
X outstr(chars[*q].ch_str);
X } else {
X msg("");
X return; /* back to cmd mode */
X }
X continue;
X }
X if ((c == '@') && (!literal_next_flag)) {
X p = buff;
X gotocmdline(YES, firstc);
X continue;
X }
X if (literal_next_flag) {
X literal_next_flag = FALSE;
X outchar('\b');
X }
X outstr(chars[c].ch_str);
X *p++ = c;
X }
X *p = '\0';
X } else {
X if (strlen(cmdline) > CMDBUFFSIZE - 2) /* should really do something
X * better here... */
X return;
X strcpy(p, cmdline);
X }
X
X /* skip any initial white space */
X for (cmd = buff; *cmd != NUL && isspace(*cmd); cmd++);
X
X /* search commands */
X c = *cmd;
X if (c == '/' || c == '?') {
X cmd++;
X /* was the command was '//' or '??' (I.E. repeat last search) */
X if ((*cmd == c) || (*cmd == NUL)) {
X if (c == '/')
X searchagain(FORWARD);
X else
X searchagain(BACKWARD);
X return;
X }
X /* If there is a matching '/' or '?' at the end, toss it */
X p = strchr(cmd, NUL);
X if (*(p - 1) == c && *(p - 2) != '\\')
X *(p - 1) = NUL;
X dosearch((c == '/') ? FORWARD : BACKWARD, cmd);
X return;
X }
X /*
X * Parse a range, if present (and update the cmd pointer).
X */
X get_range(&cmd);
X if (l_pos.linep != NULL) {
X if (LINEOF(&l_pos) > LINEOF(&u_pos)) {
X emsg("Invalid range");
X return;
X }
X }
X strcpy(cmdbuf, cmd); /* save the unmodified command */
X
X /* isolate the command and find any argument */
X for (p = cmd; *p != NUL && !isspace(*p); p++);
X if (*p == NUL)
X arg = NULL;
X else {
X *p = NUL;
X for (p++; *p != NUL && isspace(*p); p++);
X if (*p == NUL) {
X arg = NULL;
X } else {
X strcpy(argbuf, p);
X arg = argbuf;
X }
X }
X
X if (strcmp(cmd, "q!") == 0) {
X getout(0);
X }
X if (strcmp(cmd, "q") == 0) {
X if (Changed) {
X emsg(nowrtmsg);
X } else {
X getout(0);
X }
X return;
X }
X if (strcmp(cmd, "w") == 0) {
X if (arg == NULL) {
X if (Filename != NULL) {
X if (!writeit(Filename, &l_pos, &u_pos)) {
X emsg("Problems occured while writing output file");
X }
X } else {
X emsg("No output file");
X }
X } else {
X (void) writeit(arg, &l_pos, &u_pos);
X }
X return;
X }
X if (strcmp(cmd, "wq") == 0) {
X if (Filename != NULL) {
X if (writeit(Filename, (LPtr *) NULL, (LPtr *) NULL)) {
X getout(0);
X }
X } else {
X emsg("No output file");
X }
X return;
X }
X if (strcmp(cmd, "x") == 0) {
X if (Changed) {
X if (Filename != NULL) {
X if (!writeit(Filename, (LPtr *) NULL, (LPtr *) NULL)) {
X emsg("Problems occured while writing output file");
X return;
X }
X } else {
X emsg("No output file");
X return;
X }
X }
X getout(0);
X }
X if (strcmp(cmd, "f") == 0 && arg == NULL) {
X fileinfo();
X return;
X }
X if (*cmd == 'n') {
X if ((curfile + 1) < numfiles) {
X /*
X * stuff ":e[!] FILE\n"
X */
X stuffReadbuff(":e");
X if (cmd[1] == '!')
X stuffReadbuff("!");
X stuffReadbuff(" ");
X stuffReadbuff(files[++curfile]);
X stuffReadbuff("\n");
X } else
X emsg("No more files!");
X return;
X }
X if (*cmd == 'p') {
X if (curfile > 0) {
X /*
X * stuff ":e[!] FILE\n"
X */
X stuffReadbuff(":e");
X if (cmd[1] == '!')
X stuffReadbuff("!");
X stuffReadbuff(" ");
X stuffReadbuff(files[--curfile]);
X stuffReadbuff("\n");
X } else
X emsg("No more files!");
X return;
X }
X if (strncmp(cmd, "rew", 3) == 0) {
X if (numfiles <= 1) /* nothing to rewind */
X return;
X curfile = 0;
X /*
X * stuff ":e[!] FILE\n"
X */
X stuffReadbuff(":e");
X if (cmd[3] == '!')
X stuffReadbuff("!");
X stuffReadbuff(" ");
X stuffReadbuff(files[0]);
X stuffReadbuff("\n");
X return;
X }
X if (strcmp(cmd, "e") == 0) {
X if (Changed)
X emsg(nowrtmsg);
X else
X (void) doecmd(arg);
X return;
X }
X if (strcmp(cmd, "e!") == 0) {
X (void) doecmd(arg);
X return;
X }
X if (strcmp(cmd, "f") == 0) {
X Filename = strsave(arg);
X filemess("");
X return;
X }
X if (strcmp(cmd, "r") == 0 || strcmp(cmd, ".r") == 0) {
X if (arg == NULL) {
X badcmd();
X return;
X }
X if (readfile(arg, Curschar, 1)) {
X emsg("Can't open file");
X return;
X }
X CHANGED;
X return;
X }
X if (strcmp(cmd, ".=") == 0) {
X smsg("line %d", cntllines(Filemem, Curschar));
X return;
X }
X if (strcmp(cmd, "$=") == 0) {
X smsg("%d", cntllines(Filemem, Fileend) - 1);
X return;
X }
X if (strncmp(cmd, "ta", 2) == 0) {
X dotag(arg, cmd[2] == '!');
X return;
X }
X if (strcmp(cmd, "set") == 0) {
X doset(arg, interactive);
X return;
X }
X if (strcmp(cmd, "help") == 0) {
X if (help())
X s_clear();
X return;
X }
X if (strcmp(cmd, "version") == 0) {
X extern char *Version;
X
X msg(Version);
X return;
X }
X if (strcmp(cmd, "sh") == 0) {
X doshell();
X return;
X }
X if (strncmp(cmd, "d", 1) == 0) {
X LINE *cp;
X int n;
X
X if (l_pos.linep == NULL)
X l_pos = *Curschar;
X if (u_pos.linep == NULL)
X u_pos = l_pos;
X
X ResetBuffers();
X n = RowNumber(&l_pos);
X AppendPositionToUndoUndobuff(0, n);
X AppendPositionToUndobuff(0, n);
X if ((Filetop->linep->next == l_pos.linep) &&
X (u_pos.linep->next == Fileend->linep))
X AppendToUndobuff("a");
X else if (u_pos.linep->next == Fileend->linep)
X AppendToUndobuff("o");
X else
X AppendToUndobuff("O");
X
X n = 0;
X cp = l_pos.linep;
X for (; cp != NULL && cp != Fileend->linep; cp = cp->next) {
X AppendToUndobuff(cp->s);
X n++;
X if (cp == u_pos.linep)
X break;
X AppendToUndobuff(NL_STR);
X }
X AppendToUndobuff(ESC_STR);
X
X if (n > 1)
X AppendNumberToUndoUndobuff(n);
X AppendToUndoUndobuff("dd");
X
X *Curschar = l_pos;
X delline(n);
X S_NOT_VALID;
X return;
X }
X if (strncmp(cmd, "s/", 2) == 0) {
X dosub(&l_pos, &u_pos, cmdbuf + 1);
X return;
X }
X if (strncmp(cmd, "g/", 2) == 0) {
X doglob(&l_pos, &u_pos, cmdbuf + 1);
X return;
X }
X /*
X * If we got a line, but no command, then go to the line.
X */
X if (*cmd == NUL && l_pos.linep != NULL) {
X if (u_pos.linep != NULL)
X *Curschar = u_pos;
X else
X *Curschar = l_pos;
X
X S_CHECK_TOPCHAR_AND_BOTCHAR;
X
X return;
X }
X badcmd();
X}
X
X/*
X * get_range - parse a range specifier
X *
X * Ranges are of the form:
X *
X * addr[,addr]
X *
X * where 'addr' is:
X *
X * % (entire file)
X * $ [+-NUM]
X * 'x [+-NUM] (where x denotes a currently defined mark)
X * . [+-NUM]
X * NUM
X *
X * The pointer *cp is updated to point to the first character following the
X * range spec. If an initial address is found, but no second, the upper bound
X * is equal to the lower.
X */
Xstatic void
Xget_range(cp)
X char **cp;
X{
X LPtr *l;
X char *p;
X
X if (**cp == '%') {
X l_pos.index = 0;
X l_pos.linep = Filetop->linep->next;
X u_pos.index = 0;
X u_pos.linep = Fileend->linep->prev;
X (*cp)++;
X return;
X }
X if ((l = get_line(cp)) == NULL)
X return;
X
X l_pos = *l;
X
X for (p = *cp; *p != NUL && isspace(*p); p++);
X
X *cp = p;
X
X if (*p != ',') { /* is there another line spec ? */
X u_pos = l_pos;
X return;
X }
X *cp = ++p;
X
X if ((l = get_line(cp)) == NULL) {
X u_pos = l_pos;
X return;
X }
X u_pos = *l;
X}
X
Xstatic LPtr *
Xget_line(cp)
X char **cp;
X{
X static LPtr pos;
X LPtr *lp;
X char *p, c;
X int lnum;
X
X pos.index = 0; /* shouldn't matter... check back later */
X
X p = *cp;
X /*
X * Determine the basic form, if present.
X */
X switch (c = *p++) {
X
X case '$':
X pos.linep = Fileend->linep->prev;
X break;
X
X case '.':
X pos.linep = Curschar->linep;
X break;
X
X case '\'':
X if ((lp = getmark(*p++)) == NULL) {
X emsg("Unknown mark");
X return (LPtr *) NULL;
X }
X pos = *lp;
X break;
X
X case '0':
X case '1':
X case '2':
X case '3':
X case '4':
X case '5':
X case '6':
X case '7':
X case '8':
X case '9':
X for (lnum = c - '0'; isdigit(*p); p++)
X lnum = (lnum * 10) + (*p - '0');
X
X if (lnum == 0)
X lnum = 1;
X
X pos = *gotoline(lnum);
X break;
X
X default:
X return (LPtr *) NULL;
X }
X
X while (*p != NUL && isspace(*p))
X p++;
X
X if (*p == '-' || *p == '+') {
X bool_t neg = (*p++ == '-');
X
X for (lnum = 0; isdigit(*p); p++)
X lnum = (lnum * 10) + (*p - '0');
X
X if (neg)
X lnum = -lnum;
X
X pos = *gotoline(cntllines(Filemem, &pos) + lnum);
X }
X *cp = p;
X return &pos;
X}
X
Xstatic void
Xbadcmd()
X{
X if (interactive)
X emsg("Unrecognized command");
X}
X
X/*
X * dotag(tag, force) - goto tag
X */
Xvoid
Xdotag(tag, force)
X char *tag;
X bool_t force;
X{
X FILE *tp, *fopen();
X char lbuf[LSIZE];
X char *fname, *str;
X
X if ((tp = fopen("tags", "r")) == NULL) {
X emsg("Can't open tags file");
X return;
X }
X while (fgets(lbuf, LSIZE, tp) != NULL) {
X if ((fname = strchr(lbuf, TAB)) == NULL) {
X emsg("Format error in tags file");
X return;
X }
X *fname++ = '\0';
X if ((str = strchr(fname, TAB)) == NULL) {
X emsg("Format error in tags file");
X return;
X }
X *str++ = '\0';
X
X if (strcmp(lbuf, tag) == 0) {
X if (!force && Changed) {
X emsg(nowrtmsg);
X return;
X }
X if (doecmd(fname)) {
X stuffReadbuff(str); /* str has \n at end */
X stuffReadbuff("\007"); /* CTRL('G') */
X fclose(tp);
X return;
X }
X }
X }
X emsg("tag not found");
X fclose(tp);
X}
X
Xstatic bool_t
Xdoecmd(arg)
X char *arg;
X{
X int line = 1; /* line # to go to in new file */
X
X if (arg != NULL) {
X /*
X * First detect a ":e" on the current file. This is mainly for ":ta"
X * commands where the destination is within the current file.
X */
X if (Filename != NULL) {
X if (strcmp(arg, Filename) == 0) {
X if (!Changed) {
X return TRUE;
X }
X }
X }
X if (strcmp(arg, "#") == 0) { /* alternate */
X char *s = Filename;
X
X if (altfile == NULL) {
X emsg("No alternate file");
X return FALSE;
X }
X Filename = altfile;
X altfile = s;
X line = altline;
X altline = cntllines(Filemem, Curschar);
X } else {
X altfile = Filename;
X altline = cntllines(Filemem, Curschar);
X Filename = strsave(arg);
X }
X }
X if (Filename == NULL) {
X emsg("No filename");
X return FALSE;
X }
X /* clear mem and read file */
X freeall();
X filealloc();
X UNCHANGED;
X
X if (readfile(Filename, Filemem, 0)) {
X emsg("Can't open file");
X return FALSE;
X }
X *Topchar = *Curschar;
X if (line != 1) {
X stuffnumReadbuff(line);
X stuffReadbuff("G");
X }
X setpcmark();
X
X return TRUE;
X}
X
Xstatic void
Xdoshell()
X{
X char *sh, *getenv();
X
X sh = getenv("SHELL");
X if (sh == NULL) {
X emsg("Shell variable not set");
X return;
X }
X gotocmdline(YES, NUL);
X
X if (system(sh) < 0) {
X emsg("Exec failed");
X return;
X }
X wait_return();
X}
X
Xvoid
Xgotocmdline(clr, firstc)
X bool_t clr;
X char firstc;
X{
X windgoto(Rows - 1, 0);
X if (clr)
X outstr(T_EL); /* clear the bottom line */
X if (firstc)
X outchar(firstc);
X}
X
X/*
X * msg(s) - displays the string 's' on the status line
X */
Xvoid
Xmsg(s)
X char *s;
X{
X gotocmdline(YES, NUL);
X outstr(s);
X#ifdef AMIGA
X flushbuf();
X#endif
X#ifdef BSD
X flushbuf();
X#endif
X}
X
X/* VARARGS */
Xvoid
Xsmsg(s, a1, a2, a3, a4, a5, a6, a7, a8, a9)
X char *s;
X int a1, a2, a3, a4, a5, a6, a7, a8, a9;
X{
X char sbuf[MAX_COLUMNS + 1];
X
X sprintf(sbuf, s, a1, a2, a3, a4, a5, a6, a7, a8, a9);
X msg(sbuf);
X}
X
X/*
X * emsg() - display an error message
X *
X * Rings the bell, if appropriate, and calls message() to do the real work
X */
Xvoid
Xemsg(s)
X char *s;
X{
X UndoInProgress = FALSE;
X RedrawingDisabled = FALSE;
X
X if (P(P_EB))
X beep();
X outstr(T_TI);
X msg(s);
X outstr(T_TP);
X#ifdef AMIGA
X flushbuf();
X#endif
X#ifdef BSD
X flushbuf();
X#endif
X}
X
Xvoid
Xwait_return()
X{
X char c;
X
X outstr("Press RETURN to continue");
X do {
X c = vgetc();
X } while (c != '\r' && c != '\n');
X
X s_clear();
X}
SHAR_EOF
echo "extracting dec.c"
sed 's/^X//' << \SHAR_EOF > dec.c
X/*
X * STEVIE - Simply Try this Editor for VI Enthusiasts
X *
X * Code Contributions By : Tim Thompson twitch!tjt
X * Tony Andrews onecom!wldrdg!tony
X * G. R. (Fred) Walter watmath!watcgl!grwalter
X */
X
X#include "stevie.h"
X
X/*
X * dec(p)
X *
X * Decrement the line pointer 'p' crossing line boundaries as necessary. Return
X * 1 when crossing a line, -1 when at start of file, 0 otherwise.
X */
Xint
Xdec(lp)
X register LPtr *lp;
X{
X if (lp->index > 0) { /* still within line */
X lp->index--;
X return 0;
X }
X if (lp->linep->prev != Filetop->linep) { /* there is a prior line */
X lp->linep = lp->linep->prev;
X lp->index = strlen(lp->linep->s);
X return 1;
X }
X lp->index = 0; /* stick at first char */
X return -1; /* at start of file */
X}
SHAR_EOF
echo "extracting dos.c"
sed 's/^X//' << \SHAR_EOF > dos.c
X/*
X * DOS System-dependent routines.
X *
X * System-specific code for MS-DOS. This has been tested with
X * MSDOS 3.3 on an AT. Also, the console driver "nansi.sys" is
X * required.
X *
X */
X
X#include <dos.h>
X#include "stevie.h"
X
X/*
X * inchar() - get a character from the keyboard
X */
Xint
Xinchar()
X{
X int c;
X
X for (;; beep()) { /* loop until we get a valid character */
X
X flushbuf(); /* flush any pending output */
X
X switch (c = getch()) {
X case 0x1e:
X return K_CGRAVE;
X case 0: /* special key */
X if (State != NORMAL) {
X c = getch(); /* throw away next char */
X continue; /* and loop for another char */
X }
X switch (c = getch()) {
X case 0x50:
X return K_DARROW;
X case 0x48:
X return K_UARROW;
X case 0x4b:
X return K_LARROW;
X case 0x4d:
X return K_RARROW;
X case 0x52:
X return K_INSERT;
X case 0x47:
X stuffReadbuff("1G");
X return -1;
X case 0x4f:
X stuffReadbuff("G");
X return -1;
X case 0x51:
X stuffReadbuff(mkstr(CTRL('F')));
X return -1;
X case 0x49:
X stuffReadbuff(mkstr(CTRL('B')));
X return -1;
X /*
X * Hard-code some useful function key macros.
X */
X case 0x3b: /* F1 */
X stuffReadbuff(":p\n");
X return -1;
X case 0x54: /* SF1 */
X stuffReadbuff(":p!\n");
X return -1;
X case 0x3c: /* F2 */
X stuffReadbuff(":n\n");
X return -1;
X case 0x55: /* SF2 */
X stuffReadbuff(":n!\n");
X return -1;
X case 0x3d: /* F3 */
X stuffReadbuff(":e #\n");
X return -1;
X case 0x3e: /* F4 */
X stuffReadbuff(":rew\n");
X return -1;
X case 0x57: /* SF4 */
X stuffReadbuff(":rew!\n");
X return -1;
X case 0x3f: /* F5 */
X stuffReadbuff("[[");
X return -1;
X case 0x40: /* F6 */
X stuffReadbuff("]]");
X return -1;
X case 0x41: /* F7 */
X stuffReadbuff("<<");
X return -1;
X case 0x42: /* F8 */
X stuffReadbuff(">>");
X return -1;
X case 0x43: /* F9 */
X stuffReadbuff(":x\n");
X return -1;
X case 0x44: /* F10 */
X stuffReadbuff(":help\n");
X return -1;
X default:
X break;
X }
X break;
X
X default:
X return c;
X }
X }
X}
X
X#define BSIZE 2048
Xstatic char outbuf[BSIZE];
Xstatic int bpos = 0;
X
Xflushbuf()
X{
X if (bpos != 0)
X write(1, outbuf, bpos);
X bpos = 0;
X}
X
X/*
X * Macro to output a character. Used within this file for speed.
X */
X#define outone(c) outbuf[bpos++] = c; if (bpos >= BSIZE) flushbuf()
X
X/*
X * Function version for use outside this file.
X */
Xvoid
Xoutchar(c)
X register char c;
X{
X outbuf[bpos++] = c;
X if (bpos >= BSIZE)
X flushbuf();
X}
X
Xstatic char cell[2] = {0, 7};
X
X/*
X * outstr(s) - write a string to the console
X */
Xvoid
Xoutstr(s)
X register char *s;
X{
X while (*s) {
X outone(*s++);
X }
X}
X
Xvoid
Xbeep()
X{
X if (RedrawingDisabled)
X return;
X
X outone('\007');
X}
X
Xvoid
Xsleep(n)
X int n;
X{
X /*
X * Should do something reasonable here.
X */
X}
X
Xvoid
Xdelay()
X{
X long l;
X
X flushbuf();
X /*
X * Should do something better here...
X */
X for (l = 0; l < 5000; l++);
X}
X
Xvoid
Xwindinit()
X{
X Columns = 80;
X P(P_LI) = Rows = 25;
X}
X
Xvoid
Xwindexit(r)
X int r;
X{
X flushbuf();
X exit(r);
X}
X
Xvoid
Xwindgoto(r, c)
X register int r, c;
X{
X union REGS rr;
X
X flushbuf();
X rr.h.dh = r;
X rr.h.dl = c;
X rr.x.bx = 0;
X rr.x.ax = 0x0200;
X int86(0x10, &rr, &rr);
X}
X
XFILE *
Xfopenb(fname, mode)
X char *fname;
X char *mode;
X{
X FILE *fopen();
X char modestr[16];
X
X sprintf(modestr, "%sb", mode);
X return fopen(fname, modestr);
X}
SHAR_EOF
echo "extracting dos.h"
sed 's/^X//' << \SHAR_EOF > dos.h
X/*
X * MS DOS Machine-dependent routines.
X */
X
Xint inchar();
Xvoid outchar();
Xvoid outstr();
Xvoid beep();
Xvoid windinit();
Xvoid windexit();
Xvoid windgoto();
Xvoid delay();
Xvoid sleep();
SHAR_EOF
echo "extracting edit.c"
sed 's/^X//' << \SHAR_EOF > edit.c
X/*
X * STEVIE - Simply Try this Editor for VI Enthusiasts
X *
X * Code Contributions By : Tim Thompson twitch!tjt
X * Tony Andrews onecom!wldrdg!tony
X * G. R. (Fred) Walter watmath!watcgl!grwalter
X */
X
X#include "stevie.h"
X
X/*
X * This flag is used to make auto-indent work right on lines where only a
X * <RETURN> or <ESC> is typed. It is set when an auto-indent is done, and
X * reset when any other editting is done on the line. If an <ESC> or <RETURN>
X * is received, and did_ai is TRUE, the line is truncated.
X */
Xbool_t did_ai = FALSE;
X
Xvoid
Xedit()
X{
X char c;
X bool_t literal_next_flag = FALSE;
X
X Prenum = 0;
X
X /* position the display and the cursor at the top of the file. */
X *Topchar = *Filemem;
X *Curschar = *Filemem;
X Cursrow = Curscol = 0;
X
X s_refresh(NOT_VALID);
X
X for (;;) {
X
X if (!RedrawingDisabled) {
X /* Figure out where the cursor is based on Curschar. */
X cursupdate(UPDATE_CURSOR);
X windgoto(Cursrow, Curscol);
X }
X c = vgetc();
X
X if (State == NORMAL) {
X /* We're in the normal (non-insert) mode. */
X
X /* Pick up any leading digits and compute 'Prenum' */
X if (isascii(c)) { /* must disallow special chars from "ascii.h" */
X if ((Prenum > 0 && isdigit(c)) || (isdigit(c) && c != '0')) {
X Prenum = Prenum * 10 + (c - '0');
X continue;
X }
X }
X /* execute the command */
X normal(c);
X Prenum = 0;
X
X } else {
X if (c == CTRL('V') && !literal_next_flag) {
X literal_next_flag = TRUE;
X outchar('^');
X continue;
X }
X if (literal_next_flag) {
X literal_next_flag = FALSE;
X outchar('\b');
X if (c != NL) {
X did_ai = FALSE;
X insertchar(c);
X continue;
X }
X }
X switch (c) { /* We're in insert mode */
X
X case ESC: /* an escape ends input mode */
X doESCkey:
X /*
X * If we just did an auto-indent, truncate the line, and put
X * the cursor back.
X */
X if (did_ai) {
X Curschar->linep->s[0] = NUL;
X Curschar->index = 0;
X did_ai = FALSE;
X }
X set_want_col = TRUE;
X
X /*
X * The cursor should end up on the last inserted character.
X * This is an attempt to match the real 'vi', but it may not
X * be quite right yet.
X */
X if (Curschar->index != 0) {
X if (gchar(Curschar) == NUL)
X dec(Curschar);
X else if (Insbuffptr != NULL)
X dec(Curschar);
X }
X State = NORMAL;
X msg("");
X
X if (!UndoInProgress) {
X int n;
X char *p;
X
X if (last_command == 'o')
X AppendToUndobuff(UNDO_SHIFTJ_STR);
X
X if (Insbuffptr != NULL) {
X if (last_command == 'O')
X AppendToUndobuff("0");
X AppendToRedobuff(Insbuff);
X AppendToUndoUndobuff(Insbuff);
X n = 0;
X for (p = Insbuff; *p != NUL; p++) {
X if (*p == NL) {
X if (n) {
X AppendNumberToUndobuff(n);
X AppendToUndobuff("dl");
X n = 0;
X }
X AppendToUndobuff(UNDO_SHIFTJ_STR);
X } else
X n++;
X }
X if (n) {
X AppendNumberToUndobuff(n);
X AppendToUndobuff("dl");
X }
X }
X if (last_command == 'c') {
X AppendToUndobuff(mkstr(last_command_char));
X AppendToUndobuff(Yankbuff);
X AppendToUndobuff(ESC_STR);
X }
X AppendToRedobuff(ESC_STR);
X AppendToUndoUndobuff(ESC_STR);
X if (last_command == 'O')
X AppendToUndobuff(UNDO_SHIFTJ_STR);
X }
X break;
X
X case CTRL('D'):
X /*
X * Control-D is treated as a backspace in insert mode to make
X * auto-indent easier. This isn't completely compatible with
X * vi, but it's a lot easier than doing it exactly right, and
X * the difference isn't very noticeable.
X */
X case BS:
X /* can't backup past starting point */
X if (Curschar->linep == Insstart->linep &&
X Curschar->index <= Insstart->index) {
X beep();
X break;
X }
X /* can't backup to a previous line */
X if (Curschar->linep != Insstart->linep &&
X Curschar->index <= 0) {
X beep();
X break;
X }
X did_ai = FALSE;
X dec(Curschar);
X delchar(TRUE, FALSE);
X /*
X * It's a little strange to put backspaces into the redo
X * buffer, but it makes auto-indent a lot easier to deal
X * with.
X */
X AppendToInsbuff(BS_STR);
X if (!RedrawingDisabled) /* screen will be fixed later */
X S_LINE_NOT_VALID;
X break;
X
X case CR:
X case NL:
X AppendToInsbuff(NL_STR);
X if (!OpenForward(!RedrawingDisabled))
X goto doESCkey; /* out of memory */
X break;
X
X default:
X did_ai = FALSE;
X insertchar(c);
X break;
X }
X }
X }
X}
X
X/*
X * Special characters in this context are those that need processing other
X * than the simple insertion that can be performed here. This includes ESC
X * which terminates the insert, and CR/NL which need special processing to
X * open up a new line. This routine tries to optimize insertions performed by
X * the "redo", "undo" or "put" commands, so it needs to know when it should
X * stop and defer processing to the "normal" mechanism.
X */
X#define ISSPECIAL(c) ((c) == BS || (c) == NL || (c) == CR || (c) == ESC)
X
Xvoid
Xinsertchar(c)
X char c;
X{
X if (anyinput()) { /* If there's any pending input, grab up to
X * MAX_COLUMNS at once. */
X char p[MAX_COLUMNS + 1];
X int i;
X
X p[0] = c;
X i = 1;
X c = vpeekc();
X while (!ISSPECIAL(c) && anyinput() && (i < MAX_COLUMNS)) {
X p[i++] = vgetc();
X c = vpeekc();
X }
X p[i] = '\0';
X insstr(p);
X AppendToInsbuff(p);
X } else {
X inschar(c);
X AppendToInsbuff(mkstr(c));
X }
X
X if (!RedrawingDisabled) /* screen will be fixed later */
X S_LINE_NOT_VALID;
X}
X
Xvoid
Xgetout(r)
X int r;
X{
X windgoto(Rows - 1, 0);
X outchar('\r');
X outchar('\n');
X windexit(r);
X}
X
Xvoid
Xscrolldown(nlines)
X int nlines;
X{
X register LPtr *p;
X
X S_MUST_UPDATE_BOTCHAR;
X S_CHECK_TOPCHAR_AND_BOTCHAR;
X
X /* Scroll up 'nlines' lines. */
X while (nlines--) {
X p = prevline(Topchar);
X if (p == NULL)
X break;
X Topchar->linep = p->linep;
X }
X /*
X * The calling routine must make sure that Curschar is in the correct
X * place with relation to Botchar.
X */
X}
X
Xvoid
Xscrollup(nlines)
X int nlines;
X{
X register LPtr *p;
X
X S_MUST_UPDATE_BOTCHAR;
X S_CHECK_TOPCHAR_AND_BOTCHAR;
X
X /* Scroll down 'nlines' lines. */
X while (nlines--) {
X p = nextline(Topchar);
X if (p == NULL)
X break;
X Topchar->linep = p->linep;
X }
X /*
X * The calling routine must make sure that Curschar is in the correct
X * place with relation to Topchar.
X */
X}
X
X/*
X * oneright oneleft onedown oneup
X *
X * Move one char {right,left,down,up}. Return TRUE when sucessful, FALSE when
X * we hit a boundary (of a line, or the file).
X */
X
Xbool_t
Xoneright()
X{
X set_want_col = TRUE;
X
X switch (inc(Curschar)) {
X
X case 0:
X return TRUE;
X
X case 1:
X dec(Curschar); /* crossed a line, so back up */
X /* FALLTHROUGH */
X case -1:
X return FALSE;
X }
X
X return FALSE; /* PARANOIA: should never reach here */
X}
X
Xbool_t
Xoneleft()
X{
X set_want_col = TRUE;
X
X switch (dec(Curschar)) {
X
X case 0:
X return TRUE;
X
X case 1:
X inc(Curschar); /* crossed a line, so back up */
X /* FALLTHROUGH */
X case -1:
X return FALSE;
X }
X
X return FALSE; /* PARANOIA: should never reach here */
X}
X
Xvoid
Xbeginline(flag)
X bool_t flag;
X{
X while (oneleft());
X if (flag) {
X while (isspace(gchar(Curschar)) && oneright());
X }
X set_want_col = TRUE;
X}
X
Xbool_t
Xoneup(n)
X register int n;
X{
X register int k;
X
X S_CHECK_TOPCHAR_AND_BOTCHAR;
X
X for (k = 0; k < n; k++) {
X if (Curschar->linep->prev == Filetop->linep) {
X if (k > 0)
X break;
X else
X return FALSE;
X }
X Curschar->linep = Curschar->linep->prev;
X }
X
X /* try to advance to the column we want to be at */
X Curschar->index = 0;
X coladvance(Curschar, Curswant);
X return TRUE;
X}
X
Xbool_t
Xonedown(n)
X register int n;
X{
X register int k;
X
X S_CHECK_TOPCHAR_AND_BOTCHAR;
X
X for (k = 0; k < n; k++) {
X if (Curschar->linep->next == Fileend->linep) {
X if (k > 0)
X break;
X else
X return FALSE;
X }
X Curschar->linep = Curschar->linep->next;
X }
X
X /* try to advance to the column we want to be at */
X Curschar->index = 0;
X coladvance(Curschar, Curswant);
X return TRUE;
X}
SHAR_EOF
echo "extracting env.h"
sed 's/^X//' << \SHAR_EOF > env.h
X/*
X * STEVIE - Simply Try this Editor for VI Enthusiasts
X *
X * Code Contributions By : Tim Thompson twitch!tjt
X * Tony Andrews onecom!wldrdg!tony
X * G. R. (Fred) Walter watmath!watcgl!grwalter
X */
X
X/*
X * The defines in this file establish the environment we're compiling
X * in. Set these appropriately before compiling the editor.
X */
X
X/*
X * One (and only 1) of the following defines should be uncommented. Most of
X * the code is pretty machine-independent. Machine dependent code goes in a
X * file like tos.c or unix.c. The only other place where machine dependent
X * code goes is term.h for escape sequences.
X */
X
X#ifndef AMIGA
X# ifndef BSD
X# ifndef UNIX
X/* Defined in makefile : AMIGA Amiga */
X/* Defined in makefile : BSD BSD 4.3 */
X/* Defined in makefile : UNIX System V */
X/* #define ATARI Atari ST */
X/* #define OS2 Microsoft OS/2 */
X/* #define DOS MS DOS 3.3 */
X# endif
X# endif
X#endif
X
X/*
X * If ATARI is defined, one of the following compilers must be selected.
X */
X#ifdef ATARI
X#define MWC Mark William's C 3.0.9 */
X/* #define MEGAMAX Megamax Compiler */
X/* #define ALCYON Alcyon C compiler */
X
X# ifdef MWC
X# define AppendNumberToUndoUndobuff XX1
X# define AppendPositionToUndoUndobuff XX2
X# define FOPENB
X# endif
X
X# ifdef MEGAMAX
X# define FOPENB
X# endif
X#endif
X
X/*
X * If HELP is defined, the :help command shows a vi command summary.
X */
X#define HELP /* enable help command */
X
X/*
X * STRCSPN should be defined if the target system doesn't have the
X * routine strcspn() available. See regexp.c for details.
X */
X
X#ifdef ATARI
X#define STRCSPN
X#endif
SHAR_EOF
echo "extracting fileio.c"
sed 's/^X//' << \SHAR_EOF > fileio.c
X/*
X * STEVIE - Simply Try this Editor for VI Enthusiasts
X *
X * Code Contributions By : Tim Thompson twitch!tjt
X * Tony Andrews onecom!wldrdg!tony
X * G. R. (Fred) Walter watmath!watcgl!grwalter
X */
X
X#include "stevie.h"
X
Xvoid
Xfilemess(s)
X char *s;
X{
X sprintf(IObuff, "\"%s\" %s", ((Filename == NULL) ? "" : Filename), s);
X msg(IObuff);
X}
X
Xvoid
Xrenum()
X{
X LPtr *p;
X unsigned long l = 0;
X
X for (p = Filemem; p != NULL; p = nextline(p), l += LINEINC)
X p->linep->num = l;
X
X Fileend->linep->num = 0xffffffffL;
X}
X
X#ifdef MEGAMAX
Xoverlay "fileio"
X#endif
X
Xbool_t
Xreadfile(fname, fromp, nochangename)
X char *fname;
X LPtr *fromp;
X bool_t nochangename; /* if TRUE, don't change the Filename */
X{
X FILE *f, *fopen();
X LINE *curr;
X char buf2[80];
X int c;
X int IObuffsize = 0;
X long nchars = 0;
X int linecnt = 0;
X bool_t wasempty = bufempty();
X int nonascii = 0; /* count garbage characters */
X int nulls = 0; /* count nulls */
X bool_t incomplete = FALSE; /* was the last line incomplete? */
X bool_t toolong = FALSE; /* a line was too long */
X
X curr = fromp->linep;
X
X if (!nochangename)
X Filename = strsave(fname);
X
X f = fopen(fname, "r");
X if (f == NULL)
X return TRUE;
X
X S_NOT_VALID;
X
X filemess("");
X
X do {
X c = getc(f);
X
X if (c == EOF) {
X if (IObuffsize == 0)/* normal loop termination */
X break;
X
X /*
X * If we get EOF in the middle of a line, note the fact and
X * complete the line ourselves.
X */
X incomplete = TRUE;
X c = NL;
X }
X if (c >= 0x80) {
X c -= 0x80;
X nonascii++;
X }
X /*
X * If we reached the end of the line, OR we ran out of space for it,
X * then process the complete line.
X */
X if (c == NL || IObuffsize == (IOSIZE - 1)) {
X LINE *lp;
X
X if (c != NL)
X toolong = TRUE;
X
X IObuff[IObuffsize++] = NUL;
X lp = newline(IObuffsize);
X if (lp == NULL) {
X fprintf(stderr, "not enough memory - should never happen");
X getout(1);
X }
X strcpy(lp->s, IObuff);
X
X curr->next->prev = lp; /* new line to next one */
X lp->next = curr->next;
X
X curr->next = lp; /* new line to prior one */
X lp->prev = curr;
X
X curr = lp; /* new line becomes current */
X IObuffsize = 0;
X linecnt++;
X } else if (c == NUL) {
X nulls++; /* count and ignore nulls */
X } else {
X IObuff[IObuffsize++] = (char) c; /* normal character */
X }
X
X nchars++;
X } while (!incomplete && !toolong);
X
X fclose(f);
X
X /*
X * If the buffer was empty when we started, we have to go back and remove
X * the "dummy" line at Filemem and patch up the ptrs.
X */
X if (wasempty && linecnt != 0) {
X LINE *dummy = Filemem->linep; /* dummy line ptr */
X
X Filemem->linep = Filemem->linep->next;
X Filemem->linep->prev = Filetop->linep;
X Filetop->linep->next = Filemem->linep;
X
X Curschar->linep = Filemem->linep;
X Topchar->linep = Filemem->linep;
X
X free(dummy->s); /* free string space */
X free((char *) dummy); /* free LINE struct */
X }
X renum();
X
X if (toolong) {
X sprintf(IObuff, "\"%s\" Line too long", fname);
X msg(IObuff);
X return FALSE;
X }
X sprintf(IObuff, "\"%s\" %s%d line%s, %ld character%s",
X fname,
X incomplete ? "[Incomplete last line] " : "",
X linecnt, (linecnt > 1) ? "s" : "",
X nchars, (nchars > 1) ? "s" : "");
X
X buf2[0] = NUL;
X
X if (nonascii || nulls) {
X if (nonascii) {
X if (nulls)
X sprintf(buf2, " (%d null, %d non-ASCII)",
X nulls, nonascii);
X else
X sprintf(buf2, " (%d non-ASCII)", nonascii);
X } else
X sprintf(buf2, " (%d null)", nulls);
X }
X strcat(IObuff, buf2);
X msg(IObuff);
X
X return FALSE;
X}
X
X/*
X * writeit - write to file 'fname' lines 'start' through 'end'
X *
X * If either 'start' or 'end' contain null line pointers, the default is to use
X * the start or end of the file respectively.
X */
Xbool_t
Xwriteit(fname, start, end)
X char *fname;
X LPtr *start, *end;
X{
X FILE *f;
X FILE *fopen();
X FILE *fopenb(); /* open in binary mode, where needed */
X char *s;
X long nchars;
X int lines;
X LPtr *p;
X
X sprintf(IObuff, "\"%s\"", fname);
X msg(IObuff);
X
X /*
X * Form the backup file name - change foo.* to foo.bak - use IObuff to
X * hold the backup file name
X */
X strcpy(IObuff, fname);
X for (s = IObuff; *s && *s != '.'; s++);
X *s = NUL;
X strcat(IObuff, ".bak");
X
X /*
X * Delete any existing backup and move the current version to the backup.
X * For safety, we don't remove the backup until the write has finished
X * successfully. And if the 'backup' option is set, leave it around.
X */
X rename(fname, IObuff);
X
X f = P(P_CR) ? fopen(fname, "w") : fopenb(fname, "w");
X if (f == NULL) {
X emsg("Can't open file for writing!");
X return FALSE;
X }
X /*
X * If we were given a bound, start there. Otherwise just start at the
X * beginning of the file.
X */
X if (start == NULL || start->linep == NULL)
X p = Filemem;
X else
X p = start;
X
X lines = 0;
X nchars = 0;
X do {
X fprintf(f, "%s\n", p->linep->s);
X nchars += strlen(p->linep->s) + 1;
X lines++;
X
X /*
X * If we were given an upper bound, and we just did that line, then
X * bag it now.
X */
X if (end != NULL && end->linep != NULL) {
X if (end->linep == p->linep)
X break;
X }
X } while ((p = nextline(p)) != NULL);
X
X fclose(f);
X
X /*
X * Remove the backup unless they want it left around
X */
X if (!P(P_BK))
X remove(IObuff);
X
X sprintf(IObuff, "\"%s\" %d line%s, %ld character%s", fname,
X lines, (lines > 1) ? "s" : "",
X nchars, (nchars > 1) ? "s" : "");
X msg(IObuff);
X UNCHANGED;
X
X return TRUE;
X}
SHAR_EOF
echo "extracting format_l.c"
sed 's/^X//' << \SHAR_EOF > format_l.c
X/*
X * format_line()
X *
X * Return a pointer to a string buffer containing a formated screen line.
X *
X * By G. R. (Fred) Walter watmath!watcgl!grwalter
X */
X
X#include "stevie.h"
X
Xchar *tab_expand = " ";
X
Xchar *
Xformat_line(ptr, len)
X register char *ptr;
X int *len;
X{
X register char *dest;
X register char c;
X register int col;
X char *p_extra;
X int n_extra;
X int coff; /* column offset */
X
X dest = IObuff;
X col = 0;
X
X coff = P(P_NU) ? 8 : 0;
X
X n_extra = 0;
X p_extra = NULL;
X
X for (;;) {
X if (n_extra > 0) {
X c = *p_extra++;
X n_extra--;
X } else {
X c = *ptr++;
X while (c >= 32 && c < 127) {
X *dest++ = c;
X col++;
X if (col >= IOSIZE)
X goto DONE_FORMAT_LINE;
X c = *ptr++;
X }
X if (c == TAB) {
X if (!P(P_LS)) {
X /* tab amount depends on current column */
X p_extra = tab_expand;
X n_extra = (P(P_TS) - 1) - (col - coff) % P(P_TS);
X c = ' ';
X }
X } else if ((n_extra = chars[c].ch_size - 1) > 0) {
X p_extra = chars[c].ch_str;
X c = *p_extra++;
X } else if (c == NUL) {
X if (P(P_NU)) {
X *dest++ = '$';
X col++;
X }
X break;
X }
X }
X *dest++ = c;
X col++;
X if (col >= IOSIZE)
X break;
X }
XDONE_FORMAT_LINE:
X if (col >= IOSIZE) {
X dest--;
X col--;
X }
X *dest = NUL;
X
X if (len != NULL)
X *len = col;
X
X return (IObuff);
X}
SHAR_EOF
echo "extracting help.c"
sed 's/^X//' << \SHAR_EOF > help.c
X/*
X * STEVIE - Simply Try this Editor for VI Enthusiasts
X *
X * Code Contributions By : Tim Thompson twitch!tjt
X * Tony Andrews onecom!wldrdg!tony
X * G. R. (Fred) Walter watmath!watcgl!grwalter
X */
X
X#include "stevie.h"
X
Xextern char *Version;
X
Xstatic int helprow;
X
X#ifdef HELP
X
X#ifdef MEGAMAX
Xoverlay "help"
X#endif
X
Xstatic void longline();
X
Xbool_t
Xhelp()
X{
X outstr(T_ED);
X windgoto(helprow = 0, 0);
X
X longline("\
XPositioning within file\n\
X=======================\n\
X^F\t\tForward screenfull Worked on by:\n\
X^B\t\tBackward screenfull Tim Thompson\n");
X longline("\
X^D\t\tscroll down half screen Tony Andrews\n\
X^U\t\tscroll up half screen G.R. (Fred) Walter\n");
X longline("\
XG\t\tGoto line (end default)\n\
X]]\t\tnext function\n\
X[[\t\tprevious function\n\
X/re\t\tnext occurence of regular expression 're'\n");
X longline("\
X?re\t\tprior occurence of regular expression 're'\n\
Xn\t\trepeat last / or ?\n\
XN\t\treverse last / or ?\n\
X%\t\tfind matching (, ), {, }, [, or ]\n");
X longline("\
X\n\
XAdjusting the screen\n\
X====================\n\
X^L\t\tRedraw the screen\n\
X^E\t\tscroll window down 1 line\n\
X^Y\t\tscroll window up 1 line\n");
X longline("\
Xz<RETURN>\tredraw, current line at top\n\
Xz-\t\t... at bottom\n\
Xz.\t\t... at center\n");
X
X windgoto(0, 32);
X longline(Version);
X#ifdef AMIGA
X longline(" ");
X longline(__DATE__);
X longline(" ");
X longline(__TIME__);
X#endif
X
X windgoto(helprow = Rows - 2, 47);
X longline("<Press space bar to continue>\n");
X windgoto(helprow = Rows - 1, 47);
X longline("<Any other key will quit>");
X
X if (vgetc() != ' ')
X return TRUE;
X
X outstr(T_ED);
X windgoto(helprow = 0, 0);
X
X longline("\
XCharacter Positioning\n\
X=====================\n\
X^\t\tfirst non-white\n\
X0\t\tbeginning of line\n\
X$\t\tend of line\n\
Xh\t\tbackward\n");
X longline("\
Xl\t\tforward\n\
X^H\t\tsame as h\n\
Xspace\t\tsame as l\n\
Xfx\t\tfind 'x' forward\n");
X longline("\
XFx\t\tfind 'x' backward\n\
Xtx\t\tupto 'x' forward\n\
XTx\t\tupto 'x' backward\n\
X;\t\tRepeat last f, F, t, or T\n");
X longline("\
X,\t\tinverse of ;\n\
X|\t\tto specified column\n\
X%\t\tfind matching (, ), {, }, [, or ]\n");
X
X windgoto(helprow = Rows - 2, 47);
X longline("<Press space bar to continue>\n");
X windgoto(helprow = Rows - 1, 47);
X longline("<Any other key will quit>");
X
X if (vgetc() != ' ')
X return TRUE;
X
X outstr(T_ED);
X windgoto(helprow = 0, 0);
X
X longline("\
XLine Positioning\n\
X================\n\
XH\t\thome window line\n\
XL\t\tlast window line\n\
XM\t\tmiddle window line\n");
X longline("\
X+\t\tnext line, at first non-white\n\
X-\t\tprevious line, at first non-white\n\
XCR\t\treturn, same as +\n\
Xj\t\tnext line, same column\n\
Xk\t\tprevious line, same column\n");
X
X longline("\
X\n\
XMarking and Returning\n\
X=====================\n\
X``\t\tprevious context\n\
X''\t\t... at first non-white in line\n");
X longline("\
Xmx\t\tmark position with letter 'x'\n\
X`x\t\tto mark 'x'\n\
X'x\t\t... at first non-white in line\n");
X
X windgoto(helprow = Rows - 2, 47);
X longline("<Press space bar to continue>\n");
X windgoto(helprow = Rows - 1, 47);
X longline("<Any other key will quit>");
X
X if (vgetc() != ' ')
X return TRUE;
X
X outstr(T_ED);
X windgoto(helprow = 0, 0);
X
X longline("\
XInsert and Replace\n\
X==================\n\
Xa\t\tappend after cursor\n\
Xi\t\tinsert before cursor\n\
XA\t\tappend at end of line\n\
XI\t\tinsert before first non-blank\n");
X longline("\
Xo\t\topen line below\n\
XO\t\topen line above\n\
Xrx\t\treplace single char with 'x'\n\
XR\t\treplace characters (not yet)\n\
X~\t\treplace character under cursor with other case\n");
X
X longline("\
X\n\
XWords, sentences, paragraphs\n\
X============================\n\
Xw\t\tword forward\n\
Xb\t\tback word\n\
Xe\t\tend of word\n\
X)\t\tto next sentence (not yet)\n\
X}\t\tto next paragraph (not yet)\n");
X longline("\
X(\t\tback sentence (not yet)\n\
X{\t\tback paragraph (not yet)\n\
XW\t\tblank delimited word\n\
XB\t\tback W\n\
XE\t\tto end of W");
X
X windgoto(helprow = Rows - 2, 47);
X longline("<Press space bar to continue>\n");
X windgoto(helprow = Rows - 1, 47);
X longline("<Any other key will quit>");
X
X if (vgetc() != ' ')
X return TRUE;
X
X outstr(T_ED);
X windgoto(helprow = 0, 0);
X
X longline("\
XUndo & Redo\n\
X=============\n\
Xu\t\tundo last change\n\
XU\t\trestore current line (not yet)\n\
X.\t\trepeat last change\n");
X
X longline("\
X\n\
XFile manipulation\n\
X=================\n");
X longline("\
X:w\t\twrite back changes\n\
X:wq\t\twrite and quit\n\
X:x\t\twrite if modified, and quit\n\
X:q\t\tquit\n\
X:q!\t\tquit, discard changes\n\
X:e name\t\tedit file 'name'\n");
X longline("\
X:e!\t\tre-edit, discard changes\n\
X:e #\t\tedit alternate file\n\
X:w name\t\twrite file 'name'\n");
X longline("\
X:n\t\tedit next file in arglist\n\
X:n args\t\tspecify new arglist (not yet)\n\
X:rew\t\trewind arglist\n\
X:f\t\thow current file and lines\n");
X longline("\
X:f file\t\tchange current file name\n\
X:ta tag\t\tto tag file entry 'tag'\n\
X^]\t\t:ta, current word is tag");
X
X windgoto(helprow = Rows - 2, 47);
X longline("<Press space bar to continue>\n");
X windgoto(helprow = Rows - 1, 47);
X longline("<Any other key will quit>");
X
X if (vgetc() != ' ')
X return TRUE;
X
X outstr(T_ED);
X windgoto(helprow = 0, 0);
X
X longline("\
XOperators (double to affect lines)\n\
X==================================\n\
Xd\t\tdelete\n\
Xc\t\tchange\n");
X longline("\
X<\t\tleft shift\n\
X>\t\tright shift\n\
Xy\t\tyank to buffer\n");
X
X longline("\n\
XYank and Put\n\
X============\n\
Xp\t\tput back text\n\
XP\t\tput before\n\
XY\t\tyank lines");
X
X windgoto(helprow = Rows - 2, 47);
X longline("<Press space bar to continue>\n");
X windgoto(helprow = Rows - 1, 47);
X longline("<Any other key will quit>");
X
X if (vgetc() != ' ')
X return TRUE;
X
X outstr(T_ED);
X windgoto(helprow = 0, 0);
X
X longline("\n\
XMiscellaneous operations\n\
X========================\n\
XC\t\tchange rest of line\n\
XD\t\tdelete rest of line\n\
Xs\t\tsubstitute chars\n");
X longline("\
XS\t\tsubstitute lines (not yet)\n\
XJ\t\tjoin lines\n\
Xx\t\tdelete characters\n\
XX\t\t... before cursor\n\
X:[range]s/search/replace/[g]\n\
X:[range]g/search[/p|/d]\n\
X:[range]d\tdelete range of lines\n");
X
X windgoto(helprow = Rows - 1, 47);
X longline("<Press any key>");
X
X vgetc();
X
X return TRUE;
X}
X
Xstatic void
Xlongline(p)
X char *p;
X{
X# ifdef AMIGA
X outstr(p);
X# else
X char *s;
X
X for (s = p; *s; s++) {
X if (*s == '\n')
X windgoto(++helprow, 0);
X else
X outchar(*s);
X }
X# endif
X}
X#else
X
Xbool_t
Xhelp()
X{
X msg("Sorry, help not configured");
X return FALSE;
X}
X#endif
SHAR_EOF
echo "extracting inc.c"
sed 's/^X//' << \SHAR_EOF > inc.c
X/*
X * STEVIE - Simply Try this Editor for VI Enthusiasts
X *
X * Code Contributions By : Tim Thompson twitch!tjt
X * Tony Andrews onecom!wldrdg!tony
X * G. R. (Fred) Walter watmath!watcgl!grwalter
X */
X
X#include "stevie.h"
X
X/*
X * inc(p)
X *
X * Increment the line pointer 'p' crossing line boundaries as necessary. Return
X * 1 when crossing a line, -1 when at end of file, 0 otherwise.
X */
Xint
Xinc(lp)
X register LPtr *lp;
X{
X register char *p = &(lp->linep->s[lp->index]);
X
X if (*p != NUL) { /* still within line */
X lp->index++;
X return ((p[1] != NUL) ? 0 : 1);
X }
X if (lp->linep->next != Fileend->linep) { /* there is a next line */
X lp->index = 0;
X lp->linep = lp->linep->next;
X return 1;
X }
X return -1;
X}
SHAR_EOF
echo "extracting keymap.h"
sed 's/^X//' << \SHAR_EOF > keymap.h
X/*
X * STEVIE - Simply Try this Editor for VI Enthusiasts
X *
X * Code Contributions By : Tim Thompson twitch!tjt
X * Tony Andrews onecom!wldrdg!tony
X * G. R. (Fred) Walter watmath!watcgl!grwalter
X */
X
X/*
X * Keycode definitions for special keys
X *
X * On systems that have any of these keys, the routine 'inchar' in the
X * machine-dependent code should return one of the codes here.
X */
X
X#define K_CGRAVE 0x1e /* control grave accent */
X
X#define K_HELP 0x80
X#define K_UNDO 0x81
X#define K_INSERT 0x82
X#define K_HOME 0x83
X#define K_UARROW 0x84
X#define K_DARROW 0x85
X#define K_LARROW 0x86
X#define K_RARROW 0x87
X#define K_SUARROW 0x88
X#define K_SDARROW 0x89
X#define K_SLARROW 0x8a
X#define K_SRARROW 0x8b
X
X#define K_F1 0x8c /* function keys */
X#define K_F2 0x8d
X#define K_F3 0x8e
X#define K_F4 0x8f
X#define K_F5 0x90
X#define K_F6 0x91
X#define K_F7 0x92
X#define K_F8 0x93
X#define K_F9 0x94
X#define K_F10 0x95
X
X#define K_SF1 0x96 /* shifted function keys */
X#define K_SF2 0x97
X#define K_SF3 0x98
X#define K_SF4 0x99
X#define K_SF5 0x9a
X#define K_SF6 0x9b
X#define K_SF7 0x9c
X#define K_SF8 0x9d
X#define K_SF9 0x9e
X#define K_SF10 0x9f
SHAR_EOF
echo "extracting linefunc.c"
sed 's/^X//' << \SHAR_EOF > linefunc.c
X/*
X * STEVIE - Simply Try this Editor for VI Enthusiasts
X *
X * Code Contributions By : Tim Thompson twitch!tjt
X * Tony Andrews onecom!wldrdg!tony
X * G. R. (Fred) Walter watmath!watcgl!grwalter
X */
X
X#include "stevie.h"
X
X/*
X * nextline(curr)
X *
X * Return a pointer to the beginning of the next line after the one referenced
X * by 'curr'. Return NULL if there is no next line (at EOF).
X */
X
XLPtr *
Xnextline(curr)
X LPtr *curr;
X{
X static LPtr next;
X
X if (curr != NULL) {
X if (curr->linep->next != Fileend->linep) {
X next.index = 0;
X next.linep = curr->linep->next;
X return &next;
X }
X }
X return (LPtr *) NULL;
X}
X
X/*
X * prevline(curr)
X *
X * Return a pointer to the beginning of the line before the one referenced by
X * 'curr'. Return NULL if there is no prior line.
X */
X
XLPtr *
Xprevline(curr)
X LPtr *curr;
X{
X static LPtr prev;
X
X if (curr != NULL) {
X if (curr->linep->prev != Filetop->linep) {
X prev.index = 0;
X prev.linep = curr->linep->prev;
X return &prev;
X }
X }
X return (LPtr *) NULL;
X}
X
X/*
X * coladvance(p,col)
X *
X * Try to advance to the specified column, starting at p.
X */
X
Xvoid
Xcoladvance(p, want_col)
X register LPtr *p;
X register int want_col;
X{
X register char c;
X register int col;
X register int incr;
X
X if (gchar(p) != NUL) { /* already at the end of line */
X for (col = 0; want_col > 0;) {
X c = gchar(p);
X if (c == TAB && !P(P_LS))
X incr = (P(P_TS) - col % P(P_TS));
X else
X incr = chars[c].ch_size;
X want_col -= incr;
X col += incr;
X
X /* Don't go past the end of the file or the line. */
X if (inc(p)) {
X dec(p);
X break;
X }
X }
X }
X}
SHAR_EOF
echo "extracting macros.h"
sed 's/^X//' << \SHAR_EOF > macros.h
X/*
X * STEVIE - Simply Try this Editor for VI Enthusiasts
X *
X * Code Contributions By : Tim Thompson twitch!tjt
X * Tony Andrews onecom!wldrdg!tony
X * G. R. (Fred) Walter watmath!watcgl!grwalter
X */
X
X/*
X * gchar(lp) - get the character at position "lp"
X */
X#define gchar(lp) ((lp)->linep->s[(lp)->index])
X
X/*
X * pchar(lp, c) - put character 'c' at position 'lp'
X */
X#define pchar(lp, c) ((lp)->linep->s[(lp)->index] = (c))
X
X/*
X * pswap(a, b) - swap two position pointers
X */
X#define pswap(a, b) { LPtr pswaptmp; pswaptmp = a; a = b; b = pswaptmp; }
X
X/*
X * Position comparisons
X */
X#define lt(a, b) ((LINEOF(a) != LINEOF(b)) \
X ? (LINEOF(a) < LINEOF(b)) : ((a)->index < (b)->index))
X
X#define ltoreq(a, b) ((LINEOF(a) != LINEOF(b)) \
X ? (LINEOF(a) < LINEOF(b)) : ((a)->index <= (b)->index))
X
X#define gt(a, b) ((LINEOF(a) != LINEOF(b)) \
X ? (LINEOF(a) > LINEOF(b)) : ((a)->index > (b)->index))
X
X#define gtoreq(a, b) ((LINEOF(a) != LINEOF(b)) \
X ? (LINEOF(a) > LINEOF(b)) : ((a)->index >= (b)->index))
X
X#define equal(a, b) (((a)->linep == (b)->linep) && ((a)->index == (b)->index))
X
X/*
X * anyinput
X *
X * Return non-zero if input is pending.
X */
X#define anyinput() (Readbuffptr != NULL)
X
X/*
X * buf1line() - return TRUE if there is only one line in file buffer
X */
X#define buf1line() (Filemem->linep->next == Fileend->linep)
X
X/*
X * bufempty() - return TRUE if the file buffer is empty
X */
X#define bufempty() (buf1line() && Filemem->linep->s[0] == NUL)
X
X/*
X * lineempty() - return TRUE if the line is empty
X */
X#define lineempty(p) ((p)->linep->s[0] == NUL)
X
X/*
X * startofline() - return TRUE if the given position is at start of line
X */
X#define startofline(p) ((p)->index == 0)
X
X/*
X * endofline() - return TRUE if the given position is at end of line
X *
X * This routine will probably never be called with a position resting on the NUL
X * byte, but handle it correctly in case it happens.
X */
X#define endofline(p) \
X ((p)->linep->s[(p)->index] == NUL || (p)->linep->s[(p)->index + 1] == NUL)
X
X/*
X * RowNumber() - return the row number (if no UndoInProgress)
X */
X#define RowNumber(p) (UndoInProgress ? 0 : cntllines(Filemem, (p)))
SHAR_EOF
echo "extracting main.c"
sed 's/^X//' << \SHAR_EOF > main.c
X/*
X * STEVIE - Simply Try this Editor for VI Enthusiasts
X *
X * Code Contributions By : Tim Thompson twitch!tjt
X * Tony Andrews onecom!wldrdg!tony
X * G. R. (Fred) Walter watmath!watcgl!grwalter
X */
X
X#ifdef AMIGA
X# include <proto/exec.h>
X#endif
X
X#include "stevie.h"
X
Xint Rows; /* Number of Rows and Columns */
Xint Columns; /* in the current window. */
X
Xint CheckTopcharAndBotchar = FALSE;
Xint MustUpdateBotchar = FALSE;
Xint ValidToCurschar = FALSE;
Xint LineNotValid = FALSE;
X
Xint NumLineSizes = -1; /* # of active LineSizes */
XLINE **LinePointers = NULL; /* Pointer to the line for LineSizes */
Xchar *LineSizes = NULL; /* Size of a line (pline output) */
X
Xchar *Filename = NULL;/* Current file name */
X
XLPtr *Filemem; /* The contents of the file, as a single
X * array. */
XLPtr *Filetop; /* Line 'above' the start of the file */
X
XLPtr *Fileend; /* Pointer to the end of the file in Filemem.
X * (It points to the byte AFTER the last
X * byte.) */
X
XLPtr *Topchar; /* Pointer to the byte in Filemem which is in
X * the upper left corner of the screen. */
X
XLPtr *Botchar; /* Pointer to the byte in Filemem which is
X * just off the bottom of the screen. */
X
XLPtr *Curschar; /* Pointer to byte in Filemem at which the
X * cursor is currently placed. */
X
Xint Curscol; /* Current position of cursor (column) */
Xint Cursrow; /* Current position of cursor (row) */
X
Xint Cursvcol; /* Current virtual column, the column number
X * of the file's actual line, as opposed to
X * the column number we're at on the screen.
X * This makes a difference on lines that span
X * more than one screen line. */
X
Xint Curswant = 0; /* The column we'd like to be at. This is
X * used try to stay in the same column
X * through up/down cursor motions. */
X
Xbool_t set_want_col; /* If set, then update Curswant the next time
X * through cursupdate() to the current
X * virtual column. */
X
Xint State = NORMAL; /* This is the current state of the command
X * interpreter. */
X
Xint Prenum = 0; /* The (optional) number before a command. */
X
XLPtr *Insstart; /* This is where the latest insert/append
X * mode started. */
X
Xbool_t Changed = FALSE;/* Set to TRUE if something in the file has
X * been changed and not written out. */
X
Xchar *IObuff; /* file reads are done, one line at a time,
X * into this buffer; as well as sprintf's */
X
Xchar *Insbuffptr = NULL;
Xchar *Insbuff; /* Each insertion gets stuffed into this
X * buffer. */
X
Xchar *Readbuffptr = NULL;
Xchar *Readbuff; /* Having this buffer allows STEVIE to easily
X * make itself do commands */
X
Xchar *Redobuffptr = NULL;
Xchar *Redobuff; /* Each command should stuff characters into
X * this buffer that will re-execute itself. */
X
Xbool_t UndoInProgress = FALSE; /* Set to TRUE if undo'ing */
Xchar *Undobuffptr = NULL;
Xchar *Undobuff; /* Each command should stuff characters into
X * this buffer that will undo its effects. */
X
Xchar *UndoUndobuffptr = NULL;
Xchar *UndoUndobuff; /* Each command should stuff characters into
X * this buffer that will undo its undo. */
X
Xchar *Yankbuffptr = NULL;
Xchar *Yankbuff; /* Yank buffer */
X
Xchar last_command = NUL; /* last command */
Xchar last_command_char = NUL; /* character needed to undo
X * last command */
X
Xbool_t RedrawingDisabled = FALSE; /* Set to TRUE if undo'ing or
X * put'ing */
X
Xchar **files; /* list of input files */
Xint numfiles; /* number of input files */
Xint curfile; /* number of the current file */
X
Xstatic void
Xusage()
X{
X fprintf(stderr, "usage: stevie [file ...]\n");
X fprintf(stderr, " stevie -t tag\n");
X fprintf(stderr, " stevie +[num] file\n");
X fprintf(stderr, " stevie +/pat file\n");
X exit(1);
X}
X
X#ifdef AMIGA
Xvoid
X#else
Xint
X#endif
Xmain(argc, argv)
X int argc;
X char **argv;
X{
X char *initstr; /* init string from the environment */
X char *tag = NULL; /* tag from command line */
X char *pat = NULL; /* pattern from command line */
X int line = -1; /* line number from command line */
X
X int atoi();
X char *getenv();
X
X#ifdef AMIGA
X {
X struct Library *DosBase;/* Used for checking version */
X
X DosBase = OpenLibrary("dos.library", 33);
X if (!DosBase) {
X fprintf(stderr,
X "\nSTEVIE requires Version 33 or later of dos.library.\n");
X exit(2);
X } else {
X CloseLibrary(DosBase);
X }
X
X/*
X * I don't think STEVIE should be exited with a break.
X */
X (void) signal(SIGINT, SIG_IGN);
X }
X#endif
X
X /*
X * Process the command line arguments.
X */
X if (argc > 1) {
X switch (argv[1][0]) {
X
X case '-': /* -t tag */
X if (argv[1][1] != 't')
X usage();
X
X if (argv[2] == NULL)
X usage();
X
X Filename = NULL;
X tag = argv[2];
X numfiles = 1;
X break;
X
X case '+': /* +n or +/pat */
X if (argv[1][1] == '/') {
X if (argv[2] == NULL)
X usage();
X Filename = strsave(argv[2]);
X pat = &(argv[1][1]);
X numfiles = 1;
X
X } else if (isdigit(argv[1][1]) || argv[1][1] == NUL) {
X if (argv[2] == NULL)
X usage();
X Filename = strsave(argv[2]);
X numfiles = 1;
X
X line = (isdigit(argv[1][1])) ?
X atoi(&(argv[1][1])) : 0;
X } else
X usage();
X
X break;
X
X default: /* must be a file name */
X Filename = strsave(argv[1]);
X files = &(argv[1]);
X numfiles = argc - 1;
X break;
X }
X } else {
X Filename = NULL;
X numfiles = 1;
X }
X curfile = 0;
X
X windinit();
X
X /*
X * Allocate LPtr structures for all the various position pointers and for
X * the many buffers.
X */
X Filetop = (LPtr *) alloc((unsigned) sizeof(LPtr));
X Filemem = (LPtr *) alloc((unsigned) sizeof(LPtr));
X Fileend = (LPtr *) alloc((unsigned) sizeof(LPtr));
X Topchar = (LPtr *) alloc((unsigned) sizeof(LPtr));
X Curschar = (LPtr *) alloc((unsigned) sizeof(LPtr));
X Botchar = (LPtr *) alloc((unsigned) sizeof(LPtr));
X Insstart = (LPtr *) alloc((unsigned) sizeof(LPtr));
X IObuff = alloc(IOSIZE);
X Insbuff = alloc(INSERT_SIZE);
X Readbuff = alloc(READSIZE);
X Redobuff = alloc(REDO_UNDO_SIZE);
X Undobuff = alloc(REDO_UNDO_SIZE);
X UndoUndobuff = alloc(REDO_UNDO_SIZE);
X Yankbuff = alloc(YANKSIZE);
X if (Filetop == NULL ||
X Filemem == NULL ||
X Fileend == NULL ||
X Topchar == NULL ||
X Curschar == NULL ||
X Botchar == NULL ||
X Insstart == NULL ||
X IObuff == NULL ||
X Insbuff == NULL ||
X Readbuff == NULL ||
X Redobuff == NULL ||
X Undobuff == NULL ||
X UndoUndobuff == NULL ||
X Yankbuff == NULL) {
X fprintf(stderr, "Can't allocate data structures\n");
X windexit(0);
X }
X screenalloc();
X filealloc(); /* Initialize Filemem, Filetop & Fileend */
X
X s_clear();
X
X initstr = getenv("EXINIT");
X if (initstr != NULL) {
X char *lp, buf[128];
X
X lp = getenv("LINES");
X if (lp != NULL) {
X sprintf(buf, "%s lines=%s", initstr, lp);
X readcmdline(':', buf);
X } else
X readcmdline(':', initstr);
X }
X if (Filename != NULL) {
X if (readfile(Filename, Filemem, FALSE))
X filemess("[New File]");
X } else
X msg("Empty Buffer");
X
X setpcmark();
X
X if (tag) {
X stuffReadbuff(":ta ");
X stuffReadbuff(tag);
X stuffReadbuff("\n");
X } else if (pat) {
X stuffReadbuff(pat);
X stuffReadbuff("\n");
X } else if (line >= 0) {
X if (line > 0)
X stuffnumReadbuff(line);
X stuffReadbuff("G");
X }
X edit();
X /* NOTREACHED */
X /* windexit(0); */
X}
X
Xvoid
XstuffReadbuff(s)
X char *s;
X{
X if (Readbuffptr == NULL) {
X if ((strlen(s) + 1) < READSIZE) {
X strcpy(Readbuff, s);
X Readbuffptr = Readbuff;
X return;
X }
X } else if ((strlen(Readbuff) + (strlen(s) + 1)) < READSIZE) {
X strcat(Readbuff, s);
X return;
X }
X emsg("Couldn't stuffReadbuff() - clearing Readbuff\n");
X *Readbuff = NUL;
X Readbuffptr = NULL;
X}
X
Xvoid
XstuffnumReadbuff(n)
X int n;
X{
X char buf[32];
X
X sprintf(buf, "%d", n);
X stuffReadbuff(buf);
X}
X
X/* OPTRESULT */
Xchar
Xvgetc()
X{
X int c;
X
X /*
X * inchar() may map special keys by using stuffReadbuff(). If it does so,
X * it returns -1 so we know to loop here to get a real char.
X */
X do {
X if (Readbuffptr != NULL) {
X char nextc = *Readbuffptr++;
X
X if (*Readbuffptr == NUL) {
X *Readbuff = NUL;
X Readbuffptr = NULL;
X }
X return (nextc);
X }
X c = inchar();
X } while (c == -1);
X
X return (char) c;
X}
X
Xchar
Xvpeekc()
X{
X if (Readbuffptr != NULL)
X return (*Readbuffptr);
X return (NUL);
X}
SHAR_EOF
echo "End of archive 2 (of 6)"
# if you want to concatenate archives, remove anything after this line
exit